#ifndef __ZDAUTHREQ_C__
#define __ZDAUTHREQ_C__

#include "zd80211.h"

U8 AuthReqState = STE_AUTH_REQ_IDLE;
static MacAddr_t AuSta;


BOOLEAN DeauthReq(Signal_t *signal)
{
	FrmDesc_t *pfrmDesc;
	MacAddr_t Sta;
	ReasonCode Rsn = RC_UNSPEC_REASON;
	U8	vapId = 0;
	
	ZDEBUG("DeauthReq");	

	memcpy((U8 *)&Sta, (U8 *)&signal->frmInfo.Sta, 6);
	Rsn = signal->frmInfo.rCode;
	pdot11Obj->StatusNotify(STA_DEAUTHED, (u8 *)&Sta);
	
	vapId = signal->vapId;
	UpdateStaStatus(&Sta, STATION_STATE_NOT_AUTH, vapId);
	
	pfrmDesc = allocFdesc();
	if(!pfrmDesc){
		//sigEnque(pMgtQ, (signal));
        printk("Out of frmDesc in %s\n",__func__);
		return TRUE;
	}
	
	mkDisAssoc_DeAuthFrm(pfrmDesc, ST_DEAUTH, &Sta, Rsn, vapId);
	sendMgtFrame(signal, pfrmDesc);
	
	return FALSE;
}


BOOLEAN AuthReq(Signal_t *signal)
{
	FrmDesc_t *pfrmDesc;
	U8 vapId = 0;
	U16 auSC = SC_SUCCESSFUL;
	
	//ZDEBUG("AuthReq");
	FPRINT("AuthReq");
	pfrmDesc = allocFdesc();
	if(!pfrmDesc){
        FPRINT("allocFdesc failed");
        printk("Out of Fdesc in %s\n",__func__);
		//sigEnque(pMgtQ, (signal));
		return TRUE;
	}
	
	memcpy((U8 *)&AuSta, (U8 *)&signal->frmInfo.Sta, 6);
	//memcpy((U8 *)&AuSta, (U8 *)&mBssId, 6);
	mkAuthFrm(pfrmDesc, &AuSta, mAuthAlg, 1, auSC, NULL, vapId);
    //This fix is to prevent a deatuh from AP right after Auth success
    // that cause start_timer again. And crash the driver.
    pdot11Obj->StopTimer(DO_AUTH); 
	pdot11Obj->StartTimer(AUTH_TIMEOUT, DO_AUTH);	
	AuthReqState = STE_WAIT_AUTH_SEQ2;
	return sendMgtFrame(signal, pfrmDesc);
}


BOOLEAN AuthEven(Signal_t *signal)
{
	FrmDesc_t *pfrmDesc;
	Frame_t *rdu;
	U16 auAlg;
	U16	auSeq;
	U16 auSC;
	U8 vapId = 0;	
	MacAddr_t Sta;
	U8 ChalText[130];
		
	//ZDEBUG("AuthEven");
	FPRINT("AuthEven");
	pfrmDesc = signal->frmInfo.frmDesc;
	rdu = pfrmDesc->mpdu;
	auSeq = authSeqNum(rdu);
	auAlg = authType(rdu);
	memcpy((U8 *)&Sta, (U8 *)addr2(rdu), 6);
	if (memcmp(&AuSta, &Sta, 6) != 0){
		//FPRINT("Not for my Auth AP");
		goto auth_release;
	}	
	
	if ((AuthReqState == STE_WAIT_AUTH_SEQ2) && (auSeq != 2)){
		FPRINT("Seq!= 2");
		goto auth_release;
	}	
		
	if ((AuthReqState == STE_WAIT_AUTH_SEQ4) && (auSeq != 4)){
		FPRINT("Seq!= 4");
		goto auth_release;	
	}	
	
	auSC = authStatus(rdu);
	if (auSC != SC_SUCCESSFUL){
		FPRINT("Auth Failed!!!");
		FPRINT_V("Status Code", auSC);
		goto auth_release;
	}	
		
	pdot11Obj->StopTimer(DO_AUTH);
	//FPRINT_V("auAlg", auAlg);
		
	if (AuthReqState == STE_WAIT_AUTH_SEQ4){
		UpdateStaStatus(&Sta, STATION_STATE_AUTH_KEY, vapId);
		AuthReqState = STE_AUTH_REQ_IDLE;
		
		//do Assoicate
		signal->id = SIG_ASSOC_REQ;
		signal->block = BLOCK_ASOC;
		sigEnque(pMgtQ, (signal));
		freeFdesc(pfrmDesc);
        signal->frmInfo.frmDesc = NULL;
		return FALSE;
		
	} else if (AuthReqState == STE_WAIT_AUTH_SEQ2){
		if (auAlg == OPEN_SYSTEM){
			FPRINT("Auth Success !!!");
			UpdateStaStatus(&Sta, STATION_STATE_AUTH_OPEN, vapId);
			AuthReqState = STE_AUTH_REQ_IDLE;
		
			//do Assoicate
			signal->id = SIG_ASSOC_REQ;
			signal->block = BLOCK_ASOC;
			sigEnque(pMgtQ, (signal));
			freeFdesc(pfrmDesc);
            signal->frmInfo.frmDesc = NULL;
			return FALSE;
		}
		
		if (auAlg == SHARE_KEY){
			if (!getElem(rdu, EID_CTEXT, (Element *)&ChalText[0],1, NULLOUI)){
				FPRINT("Get ChalText failed");
				goto auth_release;
			}	
			
			FPRINT("Send Auth Seq 3 frame");
			auSC = SC_SUCCESSFUL;
			mkAuthFrm(pfrmDesc, &mBssId, mAuthAlg, 3, auSC, &ChalText[2], vapId);
			pdot11Obj->StartTimer(AUTH_TIMEOUT, DO_AUTH);	
			AuthReqState = STE_WAIT_AUTH_SEQ4;
			pfrmDesc->ConfigSet |= FORCE_WEP_SET;
			return sendMgtFrame(signal, pfrmDesc);
		}	
	}	
	
auth_release:
	FPRINT("auth_release");
	freeFdesc(pfrmDesc);
    signal->frmInfo.frmDesc = NULL;
	return TRUE;	
}


BOOLEAN AuthTimeOut(Signal_t *signal)
{
	U8 vapId = 0;
	FPRINT("AuthTimeOut");
	
	if 	((AuthReqState == STE_WAIT_AUTH_SEQ2) || 


		(AuthReqState == STE_WAIT_AUTH_SEQ4)){
		UpdateStaStatus(&mBssId, STATION_STATE_NOT_AUTH, vapId);
		AuthReqState = STE_AUTH_REQ_IDLE;
	}
	
	mRequestFlag |= CONNECT_TOUT_SET;
    if(signal != NULL)
    {
        if(signal->frmInfo.frmDesc != NULL)
        {
            freeFdesc(signal->frmInfo.frmDesc);
            signal->frmInfo.frmDesc = NULL;
        }
        pdot11Obj->ReleaseBuffer(signal->buf);
        freeSignal(signal);
    }
    return FALSE;
}


BOOLEAN AuthReqEntry(Signal_t *signal)
{
	FrmDesc_t *pfrmDesc;
	
	if (AuthReqState == STE_AUTH_REQ_IDLE){
		switch(signal->id){
			case SIG_DEAUTH_REQ:
				return DeauthReq(signal);
			
			case SIG_AUTH_REQ:
				return AuthReq(signal);	
			
			default:
				goto auth_discard;	
		}	
	}else if ((AuthReqState == STE_WAIT_AUTH_SEQ2) || (AuthReqState == STE_WAIT_AUTH_SEQ4)){	
		switch(signal->id){
            case SIG_DEAUTH_REQ:
                goto auth_discard;//return TRUE;

            case SIG_AUTH_REQ:
				goto auth_discard;//return TRUE;  
                    
			case SIG_AUTH_EVEN:
				return AuthEven(signal);
			
			case SIG_TO_AUTH:
				return AuthTimeOut(signal);	
			
			default:
				goto auth_discard;		
		}	
	} else
		goto auth_discard;	
		
auth_discard:
	pfrmDesc = signal->frmInfo.frmDesc;	
    if(signal->frmInfo.frmDesc != NULL)
        freeFdesc(pfrmDesc);
    signal->frmInfo.frmDesc = NULL;
	return TRUE;		
}
#endif
